package com.zero2oneblog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zero2oneblog.entity.ApiAccessStatistics;
import com.zero2oneblog.mapper.ApiAccessStatisticsMapper;
import com.zero2oneblog.service.IApiAccessStatisticsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zero2oneblog.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author liangjiu
 * @since 2024-01-04
 */
@Service
public class ApiAccessStatisticsServiceImpl extends ServiceImpl<ApiAccessStatisticsMapper, ApiAccessStatistics> implements IApiAccessStatisticsService {

    private final Map<String, AtomicInteger> apiAccessCountMap = new ConcurrentHashMap<>();
    private final ApiAccessStatisticsMapper apiAccessStatisticsMapper; //为什么是final

    @Autowired
    public ApiAccessStatisticsServiceImpl(ApiAccessStatisticsMapper apiAccessStatisticsMapper){
        this.apiAccessStatisticsMapper = apiAccessStatisticsMapper;
    }

    @Autowired
    @Lazy //确实可以解决循环依赖的问题，但是为什么呢
    private  IApiAccessStatisticsService iApiAccessStatisticsService;

    @Autowired
    private RedisService redisService;

    @Override
    public void incrementAccessCountByDataBase(String apiName) {

        QueryWrapper<ApiAccessStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("api_name", apiName);

        ApiAccessStatistics stats = apiAccessStatisticsMapper.selectOne(queryWrapper);
//        Optional<ApiAccessStatistics> optionalStats = apiAccessStatisticsMapper.findByApiName(apiName);
//        ApiAccessStatistics stats = optionalStats.orElse(new ApiAccessStatistics());
        stats.setApiName(apiName);
        stats.setAccessCount(stats.getAccessCount() + 1);
        stats.setLastAccessedAt(LocalDateTime.now());
//        apiAccessStatisticsMapper.save(stats);  //apiAccessStatisticsMapper没有save方法
//        iApiAccessStatisticsService.save(stats); //
        iApiAccessStatisticsService.saveOrUpdate(stats); //应该用saveOrUpdate方法，因为我先在数据库里创了这条记录
    }

    @Override
    public Long getAccessCount(String apiName) {

        return apiAccessStatisticsMapper.findByApiName(apiName)
                .map(ApiAccessStatistics::getAccessCount)
                .orElse(0L);
    }


    public int getApiAccessCount(String apiName) {
        // 获取指定接口的访问次数，如果不存在则返回0

        return apiAccessCountMap.getOrDefault(apiName, new AtomicInteger(0)).get();
    }

    public void incrementApiAccessCount(String apiName) {
        // 获取或创建指定接口的 AtomicInteger 对象，进行原子加一操作
        //computeIfAbsent(apiName, k -> new AtomicInteger(0))：这个方法的作用是，如果 apiAccessCountMap 中存在指定的 apiName，则返回与该键关联的值；如果不存在，则使用提供的 lambda 表达式 k -> new AtomicInteger(0) 创建一个新值，并将其关联到指定的 apiName。换句话说，如果 apiName 在映射中不存在，就创建一个新的 AtomicInteger 对象并放入映射中。
        ////这里还有个问题，就是初始值应该是数据库里的值
        if(!apiAccessCountMap.containsKey(apiName)){ //不存在的话先查一次数据库存进atomicinteger里面
            QueryWrapper<ApiAccessStatistics> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("api_name", apiName);

            ApiAccessStatistics stats = apiAccessStatisticsMapper.selectOne(queryWrapper);
            Long count = stats.getAccessCount();
            AtomicInteger counter = new AtomicInteger(Math.toIntExact(count));
            counter.incrementAndGet(); //这里执行会有问题吗，多个线程同时访问这个接口的话
            apiAccessCountMap.put(apiName,counter);


        } else { //存在
            AtomicInteger counter = apiAccessCountMap.get(apiName);
            counter.incrementAndGet();

        }
//        AtomicInteger counter = apiAccessCountMap.computeIfAbsent(apiName, k -> new AtomicInteger(0));
//        counter.incrementAndGet();
    }

    @Override
    public void incrementAccessCountByAtomic(String apiName){
        //先更新
        incrementApiAccessCount(apiName);
        //获取原子值
        int count = getApiAccessCount(apiName);
        //
        QueryWrapper<ApiAccessStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("api_name", apiName);

        ApiAccessStatistics stats = apiAccessStatisticsMapper.selectOne(queryWrapper);

        stats.setApiName(apiName);
        stats.setAccessCount((long) count); //数据库的是BigInt
        stats.setLastAccessedAt(LocalDateTime.now());

        iApiAccessStatisticsService.saveOrUpdate(stats);



    }

    @Override
    public void incrementAccessCountByAtomicTask(String apiName) {
        //先更新
        incrementApiAccessCount(apiName);
//        //获取原子值
//        int count = getApiAccessCount(apiName);
//        //
//        QueryWrapper<ApiAccessStatistics> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("api_name", apiName);
//
//        ApiAccessStatistics stats = apiAccessStatisticsMapper.selectOne(queryWrapper);
//
//        stats.setApiName(apiName);
//        stats.setAccessCount((long) count); //数据库的是BigInt
//        stats.setLastAccessedAt(LocalDateTime.now());

//        iApiAccessStatisticsService.saveOrUpdate(stats); 此处不更新了，用定时任务更新
    }

    public void updateBytask(String apiName){

        //获取原子值
        int count = getApiAccessCount(apiName);
        //
        QueryWrapper<ApiAccessStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("api_name", apiName);

        ApiAccessStatistics stats = apiAccessStatisticsMapper.selectOne(queryWrapper);

        stats.setApiName(apiName); //这里有空值异常，还得抛出来，接口名称写错的了话就会查不到
        stats.setAccessCount((long) count); //数据库的是BigInt
        stats.setLastAccessedAt(LocalDateTime.now());

        iApiAccessStatisticsService.saveOrUpdate(stats);

    }

    public void updateRedisBytask(String apiName){

        if(redisService.keyExists(apiName))
        //获取原子值
        {
            Long count = Long.valueOf(redisService.getValue(apiName)); //还没有值的时候，会抛出NULL异常
            //
            QueryWrapper<ApiAccessStatistics> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("api_name", apiName);

            ApiAccessStatistics stats = apiAccessStatisticsMapper.selectOne(queryWrapper);

            stats.setApiName(apiName); //这里有空值异常，还得抛出来，接口名称写错的了话就会查不到
            stats.setAccessCount((long) count); //数据库的是BigInt
            stats.setLastAccessedAt(LocalDateTime.now());

            iApiAccessStatisticsService.saveOrUpdate(stats);
        }
        else{
            System.out.println("暂时没有数据入库");

        }

    }

    @Override
    public void incrementAccessCountByRedis(String apiName) {
        //
        boolean flag = redisService.keyExists(apiName);
        if(flag){ //存在
            redisService.incrementAndGetValue(apiName);
        }
        else {
            redisService.storeValue(apiName,"1");
            redisService.incrementAndGetValue(apiName);
        }

    }
}
